package com.gopay.cashier.web.controller;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

import com.gopay.cashier.common.exception.WebException;
import com.gopay.cashier.domain.bean.LoginUser;
import com.gopay.cashier.service.gsrt.GsrtService;
import com.gopay.cashier.service.riskcontrol.CallRiskControlService;
import com.gopay.cashier.web.command.BankPayWay;
import com.gopay.cashier.web.command.GopayChannelCommand;
import com.gopay.cashier.web.command.OrderInfo;
import com.gopay.common.constants.Constants;
import com.gopay.common.constants.YnFlag;
import com.gopay.common.constants.cust.CustCorpInfoConstants;
import com.gopay.common.constants.cust.CustPersonInfoConstants;
import com.gopay.common.constants.cust.UserInfoConstants;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.constants.trans.GatewaySource;
import com.gopay.common.constants.trans.OrderFeePayer;
import com.gopay.common.constants.trans.PayChannel;
import com.gopay.common.constants.trans.PayChannelType;
import com.gopay.common.constants.trans.UserType;
import com.gopay.common.constants.txncd.IntTxnCd;
import com.gopay.common.domain.UserInfo;
import com.gopay.common.domain.acps.AcctStatus;
import com.gopay.common.domain.acps.FrezCode;
import com.gopay.common.domain.acps.model.AcctMastBean;
import com.gopay.common.domain.cashier.PayDoneResult;
import com.gopay.common.domain.cashier.PayWay;
import com.gopay.common.domain.cps.CpsGenMainOrder;
import com.gopay.common.domain.cust.CustCorpInfo;
import com.gopay.common.domain.cust.CustPersonInfo;
import com.gopay.common.domain.poundage.PoundageRes;
import com.gopay.common.domain.user.UserPayPwdResult;
import com.gopay.common.exception.GopayException;
import com.gopay.common.util.PwdControlUtil;
import com.gopay.remote.order.MainOrderField;

/**
 * @author Administrator
 * 国付宝账户支付
 */
@Controller
public class GopayChannelController  extends BaseController {
    
    @Resource(name="callRiskControlService")
    private CallRiskControlService callRiskControlService;
    
    @Resource(name="gsrtService")
    private GsrtService gsrtService;

    @RequestMapping("/sec/pay/gopayChannel.shtml")
    public ModelAndView execute(GopayChannelCommand command) throws Exception {
        printRequest();
        CpsGenMainOrder order = getMainOrder(getOrderId(), true);
        // 校验
        if(!validate(command, order)){
        	return back(order);
        }

        //更新订单
        updateOrder(command);
        
        //RIMS风控监控
        //必须在更新订单之后，需要updateOrder获取订单信息
		order = getMainOrder(order.getGopayOrderId(), true);
        //rimsProcess(order);

        //调用风控二期服务校验 add by xuhui 20160811
        callRiskControlService.assess(order.getGopayOrderId(), order.getPayChannel(), null, null);
        
        // 调用cps执行支付完成处理
        completeOrder(order);
        
        return new ModelAndView(new RedirectView("gopayResult.shtml?orderKey="+getRequest().getParameter("orderKey")+"&orderId="+order.getGopayOrderId()));
    }

 

	@RequestMapping("/sec/pay/gopayChannelConfirm.shtml")
    public ModelAndView executeConfirm(GopayChannelCommand command) throws Exception {
        printRequest();
        CpsGenMainOrder order = getMainOrder(getOrderId(), true);
        // 校验
        if(!validate(command, order)){
            return back(order);
        }
        //更新订单
        updateOrder(command);
        return payConfirm(order,command.getGopayAcctId());
    }

    private  ModelAndView payConfirm(CpsGenMainOrder order,String gopayAcctId) throws WebException {
        OrderInfo orderInfo = getOrderInfo(order.getGopayOrderId());
//        DecimalFormat df = new DecimalFormat("0.00");
        ModelAndView mav = new ModelAndView("pay/p2pPayConfirm");
//        BigDecimal amt = order.getTotalOrderAmt();
        mav.addObject("payWay", BankPayWay.F.name());
        mav.addObject("payMode", "国付宝账号支付");
        mav.addObject("payAmt", orderInfo.getOrderAmt());
        mav.addObject("gopayAcctId",gopayAcctId);
        mav.addObject("orderId", order.getGopayOrderId());
        mav.addObject("needPaypwd", YnFlag.y.code);
        mav.addObject("formhash", setReqAttr(KEY_FORM_HASH, getRandom(32)));// 防止hack
        mav.addObject("order", orderInfo);
        mav.addObject("formUrl","/sec/pay/gopayConfirm.shtml?orderKey="+getRequest().getParameter("orderKey")+"&orderId="+order.getGopayOrderId());
        return mav;
    }

    private ModelAndView back(CpsGenMainOrder order)
            throws WebException {
    	HttpServletRequest request = getRequest();
    	Map<String, String> pm = new HashMap<String, String>();
//    	pm.put("orderId",order.getGopayOrderId());
    	pm.put("ch", PayChannelType.GFB_PAY.value);
    	if(request.getAttribute(FIELD_ERR_MSG)!=null && StringUtils.isNotBlank((String)request.getAttribute(FIELD_ERR_MSG))){
    		request.getSession().setAttribute(FIELD_ERR_MSG, request.getAttribute(FIELD_ERR_MSG));
    	}
    	if(request.getAttribute("dcErrMesg")!=null&&StringUtils.isNotBlank((String)request.getAttribute("dcErrMesg"))){
    		request.getSession().setAttribute("dcErrMesg", request.getAttribute("dcErrMesg"));
    	}
    	pm.put("inc", IntTxnCd._00500.value.equals(order.getGopayIntTxnCd())?"y":"n");
    	return new ModelAndView(new RedirectView(request.getContextPath()+"/pay/info.shtml?orderKey="+getRequest().getParameter("orderKey")+"&orderId="+order.getGopayOrderId()),pm);
    }
    
    @RequestMapping("/sec/pay/gopayResult.shtml")
    public ModelAndView next(HttpServletRequest request) throws WebException {
        printRequest();
    	ModelAndView mav = new ModelAndView("/pay/gopayResult");
    	OrderInfo orderInfo = getOrderInfo(request.getParameter("orderId"));
    	mav.addObject("order", orderInfo);
        return mav;
    }
    
    private void updateOrder(GopayChannelCommand command) throws WebException {
        LoginUser userInfo = getLoginUser();
        UserType userType = UserType.get(userInfo.getUser().getUserType());
        PayChannel payChannel = null;
        if (UserType.Person.equals(userType)) {
            payChannel = PayChannel._02;
        } else {
            payChannel = PayChannel._52;
        }

        Map<MainOrderField, String> values = new HashMap<MainOrderField, String>();
        values.put(MainOrderField.PAY_CHANNEL, payChannel.toString());
        values.put(MainOrderField.OUT_STLM_ID, Constants.GFB_BANK_CODE);
        values.put(MainOrderField.PAY_CUST_ID, userInfo.getUser().getCustId());

        values.put(MainOrderField.PAY_ACCT, command.getGopayAcctId());//付款方
        
        CpsGenMainOrder order = getMainOrder(getOrderId(), true);
        PoundageRes p = getPoundageRes(order,payChannel);
        if (null == p.getOrderFeePayer()) {
            logger.error("没有配置手续费承担方！no OrderFeePayer!" + p);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5051);
        }
        values.put(MainOrderField.ORDER_DEAL_AMT, p.getOrderDealAmt().toString());
        values.put(MainOrderField.ORDER_REAL_FEE_AMT, p.getOrderRealFeeAmt().toString());
        values.put(MainOrderField.TOTAL_ORDER_AMT, p.getTotalAmt().toString());
        values.put(MainOrderField.TOTAL_ORDER_FEE_AMT, p.getTotalFeeAmt().toString());
        values.put(MainOrderField.ORDER_FEE_PAYER, p.getOrderFeePayer().value);

        // 如果是收款方承担手续费，且手续费金额大于订单金额，中断交易，防止实际交易金额为负数。
        if (OrderFeePayer.REC_PAYER.equals(p.getOrderFeePayer())) {
            if (1 == p.getTotalFeeAmt().compareTo(order.getMerTxnAmt())) {
                logger.error("手续费金额大于订单金额，中断交易！pay error: feeAmt[" + p.getTotalFeeAmt() + "]>merTxnAmt["
                        + order.getMerTxnAmt() + "]! " + command + ", " + order);
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5055);
            }
        }
        try {
            logger.error("调用cps更新订单.BEGIN.call cps to update order." + command + ", " + values);
            mainOrderUpdateService.updateMany(order.getGopayOrderId(), values);
            //如果是G商融通充值，则更新G商融通充值业务表
            if(StringUtils.equals(order.getGatewaySource(), GatewaySource.GATEWAY_SOURCE_09.value)){
            	gsrtService.updateGsrtRecharge(order.getGopayOrderId());
            }
            logger.error("调用cps更新订单.END.call cps to update order." + command);
        } catch (GopayException e) {
            logger.error("调用cps更新订单出错！call cps to update order exception!" + command, e);
            throw new WebException(e.getErrCode());
        }
    }
    
    private void completeOrder(CpsGenMainOrder order) throws GopayException {
        PayDoneResult r = new PayDoneResult();
        r.setSuccess(true);
        r.setPayWay(PayWay.AcctPay);
        r.setOrderId(order.getGopayOrderId());
        logger.error("账户支付返回-调用cps执行支付完成处理.BEGIN. call cashierPayCallbackService.finish." + r);
        String result = cashierPayCallbackService.finish(r);
        logger.error("账户支付返回-调用cps执行支付完成处理.END. call cashierPayCallbackService.finish." + r);
        if (!ProcCodeConstants.PROC_CODE_000S1000.equals(result)
                && !ProcCodeConstants.PROC_CODE_100S1000.equals(result)) {
            throw new GopayException(result);
        }
        getRequest().getSession().removeAttribute(CAS_GOPAY_USER);
    	getRequest().getSession().removeAttribute(GOPAY_ORDER_ID);
    }

    private boolean validate(GopayChannelCommand command, CpsGenMainOrder order) throws GopayException {
    	HttpServletRequest request = getRequest();
    	
        if (null == order) {
            logger.error("订单不存在！order not exist!" + command);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5041);
        }
        
        if (!validateSessionKey(request,command.getFormhash())) {
            logger.error("流程异常！ 页面提交的formhash和session中的不一致！ " + order);
            throw new WebException(ProcCodeConstants.PROC_CODE_100F1002);
        }
        
        LoginUser lu = getLoginUser();
        UserInfo userInfo = lu.getUser();

        if(isP2P(order)){
            if(StringUtils.equals(order.getGopayIntTxnCd(), IntTxnCd._01300.value) && !StringUtils.equals(userInfo.getCustId(), order.getMainRecvCustId())){
                //充值交易只能给自己付款
                request.setAttribute(FIELD_ERR_MSG, "充值交易异常，不能由他人代为充值");
                return false;
            }else if(StringUtils.equals(order.getGopayIntTxnCd(), IntTxnCd._01302.value) &&  !StringUtils.equals(userInfo.getCustId(), order.getPayCustId())){
                request.setAttribute(FIELD_ERR_MSG, "转账交易异常，不能由他人代为转账");
                return false;
            }
        }else{
            if(StringUtils.equals(order.getMainRecvCustId(), userInfo.getCustId())){
                request.setAttribute(FIELD_ERR_MSG,"不能给自己付款，请退出重新登录");
                return false;
            }
        }
        if(!isP2P(order)){
            String payPwd = null;
            try {
                payPwd = PwdControlUtil.decryptPwd(request, command.getPayPassword());
            } catch (Exception e) {
                logger.error("密码解密发生错误！！ Error occurs while decrypting password!!" + command, e);
            }
            UserPayPwdResult res = userPayPwdManager.verifyPayPwd(userInfo.getUserId(), payPwd);
            if (!res.isVerifySuccess()) {
                request.setAttribute(FIELD_ERR_MSG, res.getErrorMsg());
                return false;
            }
        
            //校验动态口令卡
//            String custId=getLoginUser().getUser().getCustId();
//            boolean flag = userDcPwdManager.getDCAuth(custId);
//            String userId = getLoginUser().getUser().getUserId();
//            boolean flag = userDcPwdManager.getDCAuthbyUserId(userId);
//    		if (flag) {// 有使用的才校验
//    			String dcPass = getRequest().getParameter("dcpass");
//    			String dcErrMesg="";
//    			try {
//    				dcErrMesg = userDcPwdManager.getErrMesg(custId, dcPass);
//    			    dcErrMesg = userDcPwdManager.getErrMesgByUserId(userId, dcPass);
//    			} catch (Exception e) {
    				// TODO Auto-generated catch block
//    				request.setAttribute("dcErrMesg", "校验动态口令卡出错了");
//    				 return false;
//    			}
    			
//   			if (!"".equals(dcErrMesg)) {
//    				request.setAttribute("dcErrMesg", dcErrMesg);
//    				 return false;
//    			}

//    		}
            
            
            
            
        }


        AcctMastBean acct = acctTransService.getAccount(command.getGopayAcctId());
        if (null == acct) {
            logger.error("账户不存在,acctId=" + order.getPayAcct());
            throw new WebException(ProcCodeConstants.PROC_CODE_100E6012);
        }
        if (AcctStatus.F.equals(acct.getAccStatus())) {
            if (FrezCode.DEB.equals(acct.getFrezCode()) || FrezCode.FUL.equals(acct.getFrezCode())) {
                throw new GopayException(ProcCodeConstants.PROC_CODE_000E3018, "账户[" + order.getPayAcct() + "]处于冻结状态["
                        + acct.getFrezCode() + "]，无法出款");
            }
        }
        
        if (null == userInfo || UserInfoConstants.USER_STAT_CANCEL.equals(userInfo.getUserStat())) {
            logger.error("用户不存在或尚未登录！user not exist or not login! " + request.getRemoteUser());
            throw new WebException(ProcCodeConstants.PROC_CODE_100E2001);
        }
        if (!UserInfoConstants.USER_STAT_NORMAL.equals(userInfo.getUserStat())) {
            logger.error("用户状态异常：" + userInfo.getCustId());
            throw new WebException(ProcCodeConstants.PROC_CODE_100E2002);
        }
        
        CustCorpInfo corpInfo = custCorpInfoService.get(acct.getCustId());
        if (null != corpInfo) {// 企业用户
             if (!CustCorpInfoConstants.CORP_STAT_NORMAL.toString().equals(corpInfo.getCorpStat())) {
                 throw new WebException(ProcCodeConstants.PROC_CODE_100E5002);
             }
        } else {// 个人用户
            CustPersonInfo personInfo = custPersonInfoQueryManager.get(acct.getCustId());
            if (personInfo == null || CustPersonInfoConstants.CUST_STAT_CANCEL.equals(personInfo.getCustStat())) {
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5001);
            }
            if (!CustPersonInfoConstants.CUST_STAT_NORMAL.equals(personInfo.getCustStat())) {
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5002);
            }
        }
        if(isP2P(order)){
            //校验普通账户余额
            if(new BigDecimal(acct.getAvaAmt()).compareTo(order.getTotalOrderAmt())==-1){
                request.setAttribute(FIELD_ERR_MSG,"账户余额不足");
                return false;
            }
        }
        checkRecvCustStatus(0, order.getMainRecvCustId());
        
        return true;
    }
    
    
}
